package fregat.connector.channel;

import fregat.base.net.TCPClient;
import fregat.base.net.TCPServer;
import fregat.base.util.Logger;
import fregat.connector.ConnectorService;

import java.io.PrintStream;
import java.net.Socket;

/**
 * TCP/IP channel for a server. This server channel allows only one client to
 * connect.
 *
 * @author Alexander Mann <br><b><i>ECO_L O G</i> &nbsp Logistiksysteme GmbH</b>
 * @version 1.0
 */
public class ServerChannel extends TCPChannel {

  private TCPServer server; // TCP/IP server

  /**
   * Creates a new server channel that accepts connections on the specified port.
   * This constructor reads port and protocol from configuration file.
   *
   * @param name Configuration name of channel
   */
  public ServerChannel(String name) {
    super(name, false);

    // configuration -->
    int port = ConnectorService.getConfiguration().getConfigurationInteger("channel.config." + name + ".port");
    System.out.println(ConnectorService.resource.getString("ServerChannel_constructor_1") + " @" + port);
    // <--

    createServer(port, name);
    server.setProtocol(ConnectorService.getConfiguration().configureProtocol(name));
  }

  /**
   * Creates a new server channel with the given name and port.
   * Use this constructor, if you use <code>ServerChannel</code> standalone
   *
   * @param port Port where server waits for connects
   * @param name Name of channel
   */
  public ServerChannel(int port, String name) {
    super(name, true);
    createServer(port, name);
  }

  private void createServer(int port, String name) {
    server = new TCPServer(port,Logger.getCategory(ConnectorService.LOGGING_CATEGORY)) {
      // creates a single server-side TCP/IP client instance
      protected TCPClient connect(Socket clientSocket) {
        if (client == null || !client.isConnected()) {
          client = new TCPClient(clientSocket, Logger.getCategory(ConnectorService.LOGGING_CATEGORY)) {
            protected void received(byte[] data, PrintStream out) {
              ServerChannel.this.received(data);
            }

            public void start() {
              ServerChannel.this.connected(true);
              super.start();
            }

            public void disconnect() {
              ServerChannel.this.connected(false);
              super.disconnect();
            }
          };
          return client;
        }
        return null;
      }
    };
    server.setName(name);
  }

  /**
   * Sends data to the connected client.
   *
   * @param data Data to send
   * @return True, if send was success
   */
  public boolean send(byte[] data) {
    if (client != null && client.isConnected()) {
      if (super.send(data)) {
        return true;
      } else {
        client.disconnect();
      }
    }
    return false;
  }

  /**
   * Stops all connected listeners and the server channel.
   */
  public void shutdown() {
    server.shutdown();
    super.shutdown();
  }

  /**
   * Starts the client channel and the connected listeners.
   */
  public void start() {
    super.start();
    server.start();
  } 
}
